package com.wolfking.demo.nio.socket;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NioSocketServer {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ssc.bind(new InetSocketAddress(8888));
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);//调整缓冲区大小为1024字节
                    ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
                    Selector selector = Selector.open();
                    ssc.register(selector, SelectionKey.OP_ACCEPT);
                    while (!Thread.currentThread().isInterrupted()) {
                        selector.select();
                        Set<SelectionKey> selectionKeys = selector.selectedKeys();
                        Iterator<SelectionKey> iterator = selectionKeys.iterator();
                        while (iterator.hasNext()) {
                            SelectionKey selectionKey = iterator.next();
                            if (!selectionKey.isValid()) {
                                selectionKey.channel().close();
                                selectionKey.cancel();
                                continue;
                            }
                            try {
                                if (selectionKey.isAcceptable()) {
                                    ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
                                    SocketChannel accept = channel.accept();
                                    if (accept == null) {
                                        continue;
                                    }
                                    accept.configureBlocking(false);
                                    accept.register(selector, SelectionKey.OP_READ);
                                    System.out.println(Thread.currentThread() + " connect new socket");
                                }
                                if (selectionKey.isReadable()) {
                                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                                    readBuffer.clear();
                                    int numRead;
                                    try {
                                        numRead = socketChannel.read(readBuffer);
                                        String str = new String(readBuffer.array(), 0, numRead);
                                        System.out.println(Thread.currentThread() + " read message : " + str);
                                        socketChannel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
                                    } catch (Exception e) {
                                        socketChannel.close();
                                        selectionKey.cancel();
                                    }
                                }
                                if (selectionKey.isWritable()) {
                                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                                    String str = "write-wolfking\n";
                                    System.out.println("write:" + str);

                                    sendBuffer.clear();
                                    sendBuffer.put(str.getBytes());
                                    sendBuffer.flip();//反转，由写变为读
                                    socketChannel.write(sendBuffer);
                                    //注册读操作 下一次进行读
                                    socketChannel.register(selector, SelectionKey.OP_READ);
                                }
                            } catch (CancelledKeyException e) {
                                System.out.println("cancel " + selectionKey);
                                selectionKey.channel().close();
                                selectionKey.cancel();
                            }
                            iterator.remove();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
